/*
* Copyright (c) 2011 Connection Road.  All rights reserved.
* This program and the accompanying material are made available
* under the terms of the Eclipse Public Licnese v1.0 which is
* available at http://www.eclipse.org/legal/epl-v10.html
*/

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Windows.Forms;
using System.Diagnostics;
using CrSyncFilesForms.Utils;
using CrSyncFilesUtils;
using CrSyncFilesForms.Properties;
using Timer = System.Windows.Forms.Timer;


namespace CrSyncFilesForms
{

   public partial class CrSyncUiRun : Form
    {
       /// <summary>
       /// 
       /// </summary>
        public CrSyncUiRun()
        {
            InitializeComponent();
            Init();
        }

       /// <summary>
       /// 
       /// </summary>
       /// <param name="fileSynchronizer"></param>
       public CrSyncUiRun(IFileSynchronizer fileSynchronizer)
       {
           InitializeComponent();
           Init();
           _folderPairs = fileSynchronizer.FolderPairs;
           _fileSynchronizer = fileSynchronizer;
           ShouldProcessAll = (_folderPairs.Count >= 2) ? true : false;
           
       }

       // Statistics list view items
       private ListViewItem _itemDeletedFolder;
       private ListViewItem _itemDeletedFile;
       private ListViewItem _itemOverwritten;
       private ListViewItem _itemRename;
       private ListViewItem _itemNew;
       private ListViewItem _itemCreatedFolder;
       private ListViewItem _itemAllOperations;

       private CrSyncFileCountHolder _deletedFolder;
       private CrSyncFileCountHolder _deletedFile;
       private CrSyncFileCountHolder _overwritten;
       private CrSyncFileCountHolder _renamed;
       private CrSyncFileCountHolder _createdFolder;
       private CrSyncFileCountHolder _createdFile;
       private CrSyncFileCountHolder _allOperations;
       private BackgroundWorker _backgroundWorker;
       private IFileSynchronizer _fileSynchronizer;
       private List<FileSyncPairInfo> _folderPairs;
       private Timer _timerSyncCancel;

       private bool _cancel;
       public bool ShouldProcessAll { get; set; }
       

        private void Init()
        {
            RunStatisticsList.Clear();
            _deletedFolder = new CrSyncFileCountHolder();
            _deletedFile = new CrSyncFileCountHolder();
            _overwritten = new CrSyncFileCountHolder();
            _renamed = new CrSyncFileCountHolder();
            _createdFolder = new CrSyncFileCountHolder();
            _createdFile = new CrSyncFileCountHolder();
            _allOperations = new CrSyncFileCountHolder();
            _folderPairs = new List<FileSyncPairInfo>();
            LabelTotalFilesUntouched.Text = "";

            _timerSyncCancel = new Timer {Interval = 20000 };
            _timerSyncCancel.Tick += CallBackTimerSyncCancel;
        }

        

        private void CallBackLoad(object sender, EventArgs e)
        {
            // Color scheme
            BackColor = CRSyncColors.DialogBackGround;
            LabelTotalFilesUntouched.ForeColor = CRSyncColors.ForeColor;
            LabelDestinationPath.ForeColor = CRSyncColors.ForeColor;
            LabelSourcePath.ForeColor = CRSyncColors.ForeColor;
            LabelHeader.ForeColor = CRSyncColors.HeaderTitle;
            LabelStatTitle.ForeColor = CRSyncColors.Title;
            LabelLeftFolderTitle.ForeColor = CRSyncColors.Title;
            LabelRightFolderTitle.ForeColor = CRSyncColors.Title;

            // Draw stats table
            InitializeTableResults();

            ButtonClose.Text = Resources.TEXT_STOP;
            if (ShouldProcessAll)
            {
                LabelSourcePath.Text = Resources.TEXT_MULTIPLE_PAIRS;
                LabelDestinationPath.Text = Resources.TEXT_MULTIPLE_PAIRS;
                LabelHeader.Text = Resources.TEXT_RUNNING_MULTIPLE_PAIRS;
                Text = Resources.TEXT_RESULTS_ALL_PAIRS;
            }
            else
            {
                var currentFolderPair = _folderPairs[0];
                LabelSourcePath.Text = currentFolderPair.LeftFolder.Path;
                LabelDestinationPath.Text = currentFolderPair.RightFolder.Path;
                LabelHeader.Text = LabelHeader.Text = String.Format(Resources.TEXT_RUNNING_CRSYNCFILES_FOR, currentFolderPair.FolderPairName);
                Text = string.Format("Results for Folder Pair :  {0}", currentFolderPair.FolderPairName);
            }

            // We should have timer's and backgroundworker not built with the UI but explicity created in code.  Otherwise, it's to hard for the user who
            // is studying this code to figure out what is going on
            _backgroundWorker = new BackgroundWorker
            {
                WorkerReportsProgress = true,
                WorkerSupportsCancellation = true
            };

            _backgroundWorker.DoWork += CallBackWorker;
            _backgroundWorker.ProgressChanged += CallBackWorkerProgressChanged;
            _backgroundWorker.RunWorkerCompleted += CallBackWorkerCompleted;
            _backgroundWorker.RunWorkerAsync();

        }
        

        /// <summary>
        /// Initializes the results view
        /// </summary>
        private void InitializeTableResults(){

            RunStatisticsList.Clear();

            RunStatisticsList.Columns.Add("Operations",110);
            RunStatisticsList.Columns.Add("Successful",80);
            RunStatisticsList.Columns.Add("Failed");
            RunStatisticsList.Columns.Add("Total");

            _itemDeletedFolder = ListViewItemCreate("Delete Folder", _deletedFolder);
            _itemDeletedFile = ListViewItemCreate("Delete", _deletedFile);
            _itemOverwritten = ListViewItemCreate("Overwrite", _overwritten);
            _itemRename = ListViewItemCreate("Rename", _renamed);
            _itemNew = ListViewItemCreate("New", _createdFile);
            _itemCreatedFolder = ListViewItemCreate("Create Folder", _createdFolder);
    
            var itemSpacer = new ListViewItem(" ");
            itemSpacer.SubItems.Add("---------");
            itemSpacer.SubItems.Add("---------");
            itemSpacer.SubItems.Add("---------");

            _itemAllOperations = ListViewItemCreate("All Operations", _allOperations);

            RunStatisticsList.Items.Add(_itemDeletedFolder);
            RunStatisticsList.Items.Add(_itemDeletedFile);
            RunStatisticsList.Items.Add(_itemOverwritten);
            RunStatisticsList.Items.Add(_itemRename);
            RunStatisticsList.Items.Add(_itemNew);
            RunStatisticsList.Items.Add(_itemCreatedFolder);
            RunStatisticsList.Items.Add(itemSpacer);
            RunStatisticsList.Items.Add(_itemAllOperations);

        }

       // Method for creating list view item
        private static ListViewItem ListViewItemCreate(string itemName, CrSyncFileCountHolder countHolder)
        {
            var listViewItem = new ListViewItem(itemName);
            var ints = new List<int> { countHolder.Success, countHolder.Fail, countHolder.Total };
            foreach (var i in ints)
            {
                listViewItem.SubItems.Add(String.Format("{0}", i));
            }
            return listViewItem;
        }

       private void CallBackWorker(object sender, DoWorkEventArgs e)
        {
           
           ApplicationGlobals.SetVerboseMessage("Running actual synchronization while preview is DISABLED.");

            _fileSynchronizer.FileSyncStarted += CallBackFileSynchronizationStarted;
           _fileSynchronizer.LogMessages += CallBackFileSyncLogEventMessages;
           _fileSynchronizer.FolderPairSyncingError += CallBackFolderPairSyncError;
           _fileSynchronizer.FileSyncingError += CallBackFileSyncError;
           _fileSynchronizer.VerboseMessages += CallBackVerboseOut;
           
           // Identify if we're running in preview mode or not
           var previewFirst = _fileSynchronizer.PreviewMode;
            if(previewFirst)
            {
                //--------------------- PREVIEW MODE -----------------------------
                _fileSynchronizer.PreviewMode = true;
                _fileSynchronizer.PreviewingSync += CallBackFileSynchronizationPreviewUpdate;
                _fileSynchronizer.Synchronize(0,0);
                
                //--------------------- NON-PREVIEW MODE -------------------------
                _fileSynchronizer.PreviewMode = false; 
                _fileSynchronizer.PreviewingSync -= CallBackFileSynchronizationPreviewUpdate; // Unbind preview event

                // Clear statistic counter generated while in preview mode
                //FileSynchronizer.ResetOperationCounters();
                _fileSynchronizer.FilesSyncing += CallBackFileSynchronizationUpdate;
                _fileSynchronizer.FilesSyncingCompleted += CallBackFileSynchronizationCompleted;
                _fileSynchronizer.Synchronize(0, ApplicationGlobals.CfgDefaultPauseTime);
            }
            else
            {
                //-------------------- NON-PREVIEW MODE --------------------------
                // Clear statistic counter generated while in preview mode
                //FileSynchronizer.ResetOperationCounters();
                _fileSynchronizer.PreviewMode = false;
                _fileSynchronizer.FilesSyncing += CallBackFileSynchronizationUpdate;
                _fileSynchronizer.FilesSyncingCompleted += CallBackFileSynchronizationCompleted;
                _fileSynchronizer.Synchronize(0, ApplicationGlobals.CfgDefaultPauseTime);
            }

       }


       // Fired when main background worker is finished running.
       private void CallBackWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
       {
           LabelHeader.Text = _cancel ? Resources.TEXT_RUN_CANCELLED_EARLY : Resources.TEXT_RUN_COMPLETED;
           StatusBarProgress.StatusMessage = _cancel ? "Synchronization was cancelled by user" : Resources.TEXT_COMPLETED;
           LabelTotalFilesUntouched.Text = string.Format(Resources.TEXT_FOUND_FILES_THAT_DID_NOT_REQUIRE_ACTION, _fileSynchronizer.TotalFilesUntouched);
           StatusBarProgress.DefaultProgressBar.Style = ProgressBarStyle.Continuous;
           StatusBarProgress.DefaultProgressBar.Maximum = 1;
           StatusBarProgress.DefaultProgressBar.Value = 1;
           ButtonClose.Text = Resources.TEXT_CLOSE;
           ButtonClose.Enabled = true;

           if(_fileSynchronizer.TotalSkippedOperations >= 1)
           {
               LabelTotalSkippedOperations.Text =
                   string.Format("There were {0} operations skipped due to deselection in Preview mode.",
                                 _fileSynchronizer.TotalSkippedOperations);
               LabelTotalSkippedOperations.Visible = true;
           }

           if(_fileSynchronizer.SkippedFiles.Count >= 1)
           {
               LinkSeeError.Visible = true;
               LabelHeader.Text = "The CRSyncFiles run completed, but there were errors.";
           }
       }




       private void CallBackClose(object sender, EventArgs e)
        {
            var button = sender as Button;
            if (button != null)
                if (button.Text == Resources.TEXT_CLOSE)
                {
                    Close();
                }
                else if(button.Text == Resources.TEXT_STOP)
                {
                    LabelHeader.Text = Resources.TEXT_CANCELLATION_PENDING;
                    _fileSynchronizer.CancelPending = true;
                    _backgroundWorker.CancelAsync();
                    ButtonClose.Enabled = false;
                    _cancel = true;
                }
        }

       // Fired when the synchronization starts.
       protected virtual void CallBackFileSynchronizationStarted(object sender, FileSyncEventArgs args)
       {
           _backgroundWorker.ReportProgress(0,args);
       }


       // Background worker object progress reporting.
        private void CallBackWorkerProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            var eventArguments = e.UserState as FileSyncEventArgs;
            
            // Update progress bar
            if (eventArguments != null)
            {
                if(!eventArguments.PreviewMode)
                {
                    StatusBarProgress.DefaultProgressBar.Style = ProgressBarStyle.Continuous;
                    StatusBarProgress.DefaultProgressBar.Maximum = 100;
                    StatusBarProgress.DefaultProgressBar.Step = 1;
                    StatusBarProgress.Progress = e.ProgressPercentage;
                
                }
                else
                {
                    StatusBarProgress.DefaultProgressBar.Style = ProgressBarStyle.Marquee;
                }

                
                // Update status message
                StatusBarProgress.StatusMessage = eventArguments.Message ?? StatusBarProgress.StatusMessage;

                // Refresh stats but only update when not in preview mode.
                if (!eventArguments.PreviewMode)
                {
                    UpdateResultStatisticsList(eventArguments.FileSyncStatistics); 
                }
                
            }
        }

        // Fired when Synchronizer makes a progress update.
        private void CallBackFileSynchronizationUpdate(object sender, FileSyncEventArgs args)
        {
            var crSyncFileStatistics = args.FileSyncStatistics;
            var currentProgress = ((crSyncFileStatistics != null) && (crSyncFileStatistics.Progress.HasValue))
                                      ? crSyncFileStatistics.Progress.Value
                                      : StatusBarProgress.Progress;

            _backgroundWorker.ReportProgress(currentProgress,args); // Report progress
        }

        protected virtual void CallBackFileSynchronizationPreviewUpdate(object  sender, FileSyncEventArgs args)
        {
            var crSyncFileStatistics = args.FileSyncStatistics;
            var currentProgress = ((crSyncFileStatistics != null) && (crSyncFileStatistics.Progress.HasValue))
                                      ? crSyncFileStatistics.Progress.Value
                                      : StatusBarProgress.Progress;

            _backgroundWorker.ReportProgress(currentProgress, args); // Report progress
        }

       protected virtual void CallBackFileSyncLogEventMessages(object sender, FileSyncMessageEventArgs args)
       {
           CrSyncFilesUtility.WriteLog(args.Message,ApplicationGlobals.CrSyncLogFilePath);
       }

       protected virtual void CallBackFileSyncError(object sender, FileSyncErrorEventArgs args)
       {
           if(args.Exception != null)
           {
               var errorMessage = "[ERROR]--------------------\r\n\r\n" +
                                  "MESSAGE: " + args.Exception.Message + "\r\n\r\n" +
                                  "CULPRIT: "+ args.Exception.Source +
                                  "STACK:\r\n\r\n"+args.Exception.StackTrace;
               CrSyncFilesUtility.WriteLog(errorMessage,ApplicationGlobals.CrSyncCriticalLogFilePath);
           }
           MessageBox.Show(args.Message, "CRSyncFiles", MessageBoxButtons.OK, MessageBoxIcon.Error);
       }

       protected virtual void CallBackFolderPairSyncError(object sender, FileSyncErrorEventArgs args)
       {
           if (args.Exception != null)
           {
               var folderPairErrorMessage = "Failed to sync : " + args.FolderPair.FolderPairName+". Reason : "+args.Message;
               CrSyncFilesUtility.WriteLog(folderPairErrorMessage, ApplicationGlobals.CrSyncLogFilePath);
               if (!string.IsNullOrEmpty(args.Exception.StackTrace))
               {
                   CrSyncFilesUtility.WriteLog("STACK : " + args.Exception.StackTrace, ApplicationGlobals.CrSyncLogFilePath);
               }
           }
       }

        // Triggers when Synchronizer is done processing.
        private void CallBackFileSynchronizationCompleted(object sender, FileSyncEventArgs args)
        {

            // ProgressBar reporting
            _backgroundWorker.ReportProgress(args.FileSyncStatistics.Progress ?? 0, args);
            

            // Evnt log entries
            if (ShouldProcessAll)
            {
                ApplicationGlobals.WriteEventLog("CRSyncFiles has Successfully Run for all folder pairs",
                                                 EventLogEntryType.Information);
            }
            else
            {
                ApplicationGlobals.WriteEventLog(string.Format("CRSyncFiles has Successfully Run the following Folder Pair :  {0}",
                                                                _folderPairs[0].FolderPairName),
                                                    EventLogEntryType.Information);
                
            }

        }

       // Method for updating the listview stats
       private void UpdateResultStatisticsList(CrSyncFileStatistics crSyncFileStatistics)
       {
           if(crSyncFileStatistics != null)
           {

               var statItemDeletedFoldersSuccess = _itemDeletedFolder.SubItems[1];
               var statItemDeletedFoldersFail = _itemDeletedFolder.SubItems[2];
               var statItemDeletedFoldersTotal = _itemDeletedFolder.SubItems[3];

               var statItemDeletedFilesSucess = _itemDeletedFile.SubItems[1];
               var statItemDeletedFilesFail = _itemDeletedFile.SubItems[2];
               var statItemDeletedFilesTotal = _itemDeletedFile.SubItems[3];

               var statItemCreatedFilesSucess = _itemNew.SubItems[1];
               var statItemCreatedFilesFail = _itemNew.SubItems[2];
               var statItemCreatedFilesTotal = _itemNew.SubItems[3];

               var statItemCreatedFoldersSucess = _itemCreatedFolder.SubItems[1];
               var statItemCreatedFoldersFail = _itemCreatedFolder.SubItems[2];
               var statItemCreatedFoldersTotal = _itemCreatedFolder.SubItems[3];

               var statItemOverwrittenSuccess = _itemOverwritten.SubItems[1];
               var statItemOverwrittenFail = _itemOverwritten.SubItems[2];
               var statItemOverwrittenTotal = _itemOverwritten.SubItems[3];

               var statItemRenameSuccess = _itemRename.SubItems[1];
               var statItemRenameFail = _itemRename.SubItems[2];
               var statItemRenameTotal = _itemRename.SubItems[3];

               var statItemAllOperationSuccess = _itemAllOperations.SubItems[1];
               var statItemAllOperationFail = _itemAllOperations.SubItems[2];
               var statItemAllTotalOperation = _itemAllOperations.SubItems[3];

               if(crSyncFileStatistics.TotalDeletedFolders != null)
               {
                   statItemDeletedFoldersSuccess.Text = crSyncFileStatistics.TotalDeletedFolders.Success.ToString();
                   statItemDeletedFoldersFail.Text = crSyncFileStatistics.TotalDeletedFolders.Fail.ToString();
                   statItemDeletedFoldersTotal.Text = crSyncFileStatistics.TotalDeletedFolders.Total.ToString();
                   if(crSyncFileStatistics.TotalDeletedFolders.Fail >= 1)
                   {
                       _itemDeletedFolder.ForeColor = Color.Red;
                   }
               }

               if(crSyncFileStatistics.TotalDeletedFiles != null)
               {
                   statItemDeletedFilesSucess.Text = crSyncFileStatistics.TotalDeletedFiles.Success.ToString();
                   statItemDeletedFilesFail.Text = crSyncFileStatistics.TotalDeletedFiles.Fail.ToString();
                   statItemDeletedFilesTotal.Text = crSyncFileStatistics.TotalDeletedFiles.Total.ToString();
                   if(crSyncFileStatistics.TotalDeletedFiles.Fail >= 1)
                   {
                       _itemDeletedFile.ForeColor = Color.Red;
                   }
               }

               if (crSyncFileStatistics.TotalCreatedFiles != null)
               {
                   statItemCreatedFilesSucess.Text = crSyncFileStatistics.TotalCreatedFiles.Success.ToString();
                   statItemCreatedFilesFail.Text = crSyncFileStatistics.TotalCreatedFiles.Fail.ToString();
                   statItemCreatedFilesTotal.Text = crSyncFileStatistics.TotalCreatedFiles.Total.ToString();
                   if(crSyncFileStatistics.TotalCreatedFiles.Fail >= 1)
                   {
                       _itemNew.ForeColor = Color.Red;
                   }
               }

               if( crSyncFileStatistics.TotalCreatedFolders != null)
               {
                   statItemCreatedFoldersSucess.Text = crSyncFileStatistics.TotalCreatedFolders.Success.ToString();
                   statItemCreatedFoldersFail.Text = crSyncFileStatistics.TotalCreatedFolders.Fail.ToString();
                   statItemCreatedFoldersTotal.Text = crSyncFileStatistics.TotalCreatedFolders.Total.ToString();
                   if(crSyncFileStatistics.TotalCreatedFolders.Fail >= 1)
                   {
                       _itemCreatedFolder.ForeColor = Color.Red;
                   }
               }

               if(crSyncFileStatistics.TotalOverWrittenFiles != null)
               {
                   statItemOverwrittenSuccess.Text = crSyncFileStatistics.TotalOverWrittenFiles.Success.ToString();
                   statItemOverwrittenFail.Text = crSyncFileStatistics.TotalOverWrittenFiles.Fail.ToString();
                   statItemOverwrittenTotal.Text = crSyncFileStatistics.TotalOverWrittenFiles.Total.ToString();
                   if(crSyncFileStatistics.TotalOverWrittenFiles.Fail >= 1)
                   {
                       _itemOverwritten.ForeColor = Color.Red;
                   }
               }

               if (crSyncFileStatistics.TotalRenamedFiles != null)
               {
                   statItemRenameSuccess.Text = crSyncFileStatistics.TotalRenamedFiles.Success.ToString();
                   statItemRenameFail.Text = crSyncFileStatistics.TotalRenamedFiles.Fail.ToString();
                   statItemRenameTotal.Text = crSyncFileStatistics.TotalRenamedFiles.Total.ToString();
                   if(crSyncFileStatistics.TotalRenamedFiles.Fail >= 1)
                   {
                       _itemRename.ForeColor = Color.Red;
                   }
               }

               if(crSyncFileStatistics.TotalOperations != null)
               {
                   statItemAllOperationSuccess.Text = crSyncFileStatistics.TotalOperations.Success.ToString();
                   statItemAllOperationFail.Text = crSyncFileStatistics.TotalOperations.Fail.ToString();
                   statItemAllTotalOperation.Text = crSyncFileStatistics.TotalOperations.Total.ToString();

                   if(crSyncFileStatistics.TotalOperations.Fail >= 1)
                   {
                       _itemAllOperations.ForeColor = Color.Red;
                   }
               }

           }
       }

       protected virtual void CallBackTimerSyncCancel(object sender, EventArgs args)
       {
           if(_backgroundWorker.CancellationPending)
           {
               ApplicationGlobals.SetVerboseMessage("Synchroniation cancel pending...");
           }
           else if(_backgroundWorker.IsBusy)
           {
               ApplicationGlobals.SetVerboseMessage("Cancelling synchronization...");
               _fileSynchronizer.CancelPending = true;
               _backgroundWorker.CancelAsync();
           }
           else
           {
               ApplicationGlobals.SetVerboseMessage("Synchronization halted...");
               ButtonClose.Enabled = true;
               _timerSyncCancel.Stop();
           }
       }

       protected virtual void CallBackVerboseOut(object  sender, FileSyncMessageEventArgs args)
       {
           ApplicationGlobals.SetVerboseMessage(args.Message);
       }

       private void CallBackSeeError(object sender, LinkLabelLinkClickedEventArgs e)
       {
           Hide();
           var previewDialog = new CrSyncUiPreview(_fileSynchronizer, _fileSynchronizer.SkippedFiles);
           previewDialog.ShowDialog(Program.MainWindow);
           Close();
       }
    }
}
